﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyShowBinTree
{
    public class Common
    {
        static int radio = 50;
        static int lineHeight = 80;
        static int colWidth = 80;
        static Font font = new Font("Microsoft YaHei", 18, FontStyle.Regular);

        public static Image GetTreeImage(TreeNode root)
        {
            int depth = GetTreeDepth(root);
            int maxColumnCount = (int)Math.Pow(2, depth - 1);
            int minWidth = maxColumnCount * colWidth;
            int minHeight = depth * lineHeight;
            int valWidth = minWidth - colWidth;

            Image img = new Bitmap(minWidth, minHeight);
            Graphics g = Graphics.FromImage(img);
            g.Clear(Color.White);

            int temDepth = 1;
            Point centerP = new Point();
            centerP.X = minWidth / 2;
            centerP.Y = lineHeight / 2;

            Point leftP = new Point();
            Point rightP = new Point();
            leftP.Y = rightP.Y = centerP.Y + lineHeight;
            int margin = (int)Math.Pow(2, temDepth + 1);
            margin = valWidth / margin;
            leftP.X = centerP.X - margin;
            rightP.X = centerP.X + margin;

            if (root.left != null)
            {
                g.DrawLine(Pens.Black, centerP, leftP);
                DrawTreeNode(g, root.left, leftP, valWidth, temDepth + 1, Color.Green);
            }

            if (root.right != null)
            {
                g.DrawLine(Pens.Black, centerP, rightP);
                DrawTreeNode(g, root.right, rightP, valWidth, temDepth + 1, Color.Blue);
            }

            Rectangle rect = new Rectangle();
            rect.X = centerP.X - radio / 2;
            rect.Y = centerP.Y - radio / 2;
            rect.Width = rect.Height = radio;
            Brush brush = new SolidBrush(Color.Black);
            g.FillEllipse(brush, rect);
            StringFormat format = new StringFormat();
            format.LineAlignment = StringAlignment.Center;
            format.Alignment = StringAlignment.Center;
            g.DrawString(root.value.ToString(), font, Brushes.Yellow, rect, format);

            g.Flush();
            g.Dispose();
            return img;
        }

        public static void DrawTreeNode(Graphics g, TreeNode node, Point centerP, int valWidth, int depth, Color color)
        {
            int margin = (int)Math.Pow(2, depth + 1);
            margin = valWidth / margin;

            Point leftP = new Point();
            Point rightP = new Point();
            leftP.Y = rightP.Y = centerP.Y + lineHeight;
            leftP.X = centerP.X - margin;
            rightP.X = centerP.X + margin;
            if (node.left != null)
            {
                g.DrawLine(Pens.Black, centerP, leftP);
                DrawTreeNode(g, node.left, leftP, valWidth, depth + 1, Color.Green);
            }

            if (node.right != null)
            {
                g.DrawLine(Pens.Black, centerP, rightP);
                DrawTreeNode(g, node.right, rightP, valWidth, depth + 1, Color.Blue);
            }

            Rectangle rect = new Rectangle();
            rect.X = centerP.X - radio / 2;
            rect.Y = centerP.Y - radio / 2;
            rect.Width = rect.Height = radio;
            Brush brush = new SolidBrush(color);
            g.FillEllipse(brush, rect);
            StringFormat format = new StringFormat();
            format.LineAlignment = StringAlignment.Center;
            format.Alignment = StringAlignment.Center;
            g.DrawString(node.value.ToString(), font, Brushes.Yellow, rect, format);
        }

        public static int GetTreeDepth(TreeNode root)
        {
            if (root == null)
            {
                return 0;
            }
            int leftDepth = GetTreeDepth(root.left);
            int rightDepth = GetTreeDepth(root.right);
            return Math.Max(leftDepth, rightDepth) + 1;
        }
    }
}
